#include "function.h"
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QImage>
#include <cstring>
#include <cmath>

#define PI 3.14159
#define e  2.71828

//构造函数
Function::Function(QImage image) {
    initialImage = image;
    lastImage = image;
    finalImage = image;
}

//默认构造函数
Function::Function() {

}

//拷贝函数
void Function::copyPicture(QImage image) {
    initialImage = image;
    lastImage = image;
    finalImage = image;
}

//获取原始图片
QImage Function::getInitialImage() {
    return initialImage;
}

//获取上一张图片
QImage Function::getLastImage() {
    return lastImage;
}

//获取最新修改的图片
QImage Function::getFinalImage() {
    return finalImage;
}

//修改上一步修改的图片
void Function::setLastImage(QImage image) {
    lastImage = image;
}

//修改最新图片
void Function::setFinalImage(QImage image) {
    finalImage = image;
}

//图形变换————放大&缩小
QImage Function::changedPictureSize(double rate) {
    lastImage = finalImage;

    double a = rate / 100;

    //原图像的高宽
    int pre_width = finalImage.width();
    int pre_height = finalImage.height();

    //变化后图像的高宽
    int aft_width = pre_width * a;
    int aft_height = pre_height * a;

    //创建一个新的图像
    QImage* newImage = new QImage(aft_width, aft_height, QImage::Format_ARGB32);

    unsigned char* pre_pixel = NULL;
    unsigned char* aft_pixel = NULL;

    int x = 0, y = 0;

    for(int i = 0; i < aft_height; i++) {
        for(int j = 0; j < aft_width; j++) {
            //由左下到右上依次遍历每一个像素点，求出其对应原图的像素点坐标
            x = (int)(j / a);
            y = (int)(i / a);

            if(x == pre_width) {
                x--;
            }
            if(y == pre_height) {
                y--;
            }

            pre_pixel = finalImage.bits() + y * pre_width * 4  + x * 4;
            aft_pixel = newImage->bits() + i * aft_width * 4 + j * 4;

            //调用memcpy函数复制像素数据
            if(x >= 0 && x < pre_width && y >= 0 && y < pre_height) {
                memcpy(aft_pixel, pre_pixel, 4);
            }
        }
    }

    finalImage = *newImage;
    delete newImage;
    return finalImage;
}

//图形变换————旋转（最临近插值法）
QImage Function::revolvePicture(double a) {
    //若a为负即为逆时针旋转，a为正为顺时针旋转
    lastImage = finalImage;

    //原图像的高宽
    int pre_width = finalImage.width();
    int pre_height = finalImage.height();

    //angle为旋转度数，以弧度表示
    double angle = PI * a / 180;

    double Sin = sin(angle);
    double Cos = cos(angle);

    //计算旋转后图像的高宽
    int aft_width = pre_width * fabs(Cos) + pre_height * fabs(Sin);
    int aft_height = pre_width * fabs(Sin) + pre_height *fabs(Cos);

    //创建一个新的图像
    QImage* newImage = new QImage(aft_width, aft_height, QImage::Format_ARGB32);

    //计算要用到的数据
    double dx = -0.5 * aft_width * Cos - 0.5 * aft_height * Sin + 0.5 * pre_width;
    double dy =  0.5 * aft_width * Sin - 0.5 * aft_height * Cos + 0.5 * pre_height;

    unsigned char* pre_pixel = NULL;// 指向原始图像中需要拷贝像素的起始位置
    unsigned char* aft_pixel = NULL; // 指向被复制像素的起始位置

    int x = 0;
    int y = 0;

    //(i,j)旋转后的图像的数字坐标系对应转换到图像坐标系(x,y)
    for(int i = 0; i < aft_height; i++) {
        for(int j = 0; j < aft_width; j++) {
            //用旋转公式计算出旋转后图像的点对应的原图上的点
            x = (int)(j * Cos + i * Sin + dx);
            y = (int)(-j * Sin + i * Cos + dy);

            if(x == pre_width) {
                x--;
            }
            if(y == pre_height) {
                y--;
            }

            //bits()函数获取图像像素字节数据的首地址
            pre_pixel = finalImage.bits() + y * pre_width * 4  + x * 4;
            aft_pixel = newImage->bits() + i * aft_width * 4 + j * 4;

            //调用memcpy函数复制像素数据,将pre_pixel的4个字节长度复制到aft_pixel
            if(x >= 0 && x < pre_width && y >= 0 && y < pre_height) {
                memcpy(aft_pixel, pre_pixel, 4);
            }
        }
    }

    finalImage = *newImage;
    delete newImage;
    return finalImage;
}

//水平镜像
QImage Function::spPicture(){
    lastImage = finalImage;

    int width = finalImage.width();
    int height = finalImage.height();

    unsigned char* pre_pixel = NULL;
    unsigned char* aft_pixel = NULL;

    QImage *newImage = new QImage(width, height, QImage::Format_RGB32);
    int x = 0, y = 0;
    for(int i = 0; i < height; i++){
        for(int j = 0; j < width; j++){
            x = -j + width;
            y = i;

            if(x >= 0 && x < width && y >= 0 && y < height){
                pre_pixel = finalImage.bits() + y * width * 4  + x * 4;
                aft_pixel = newImage->bits() + i * width * 4 + j * 4;
                memcpy(aft_pixel, pre_pixel, 4);
            }
       }
   }
    finalImage = *newImage;
    delete newImage;
    return finalImage;
}

//垂直镜像
QImage Function::czPicture(){
    lastImage = finalImage;

    int width = finalImage.width();
    int height = finalImage.height();

    unsigned char* pre_pixel = NULL;
    unsigned char* aft_pixel = NULL;

    QImage *newImage = new QImage(width, height, QImage::Format_RGB32);
    int x = 0, y = 0;
    for(int i = 0; i < height; i++){
        for(int j = 0; j < width; j++){
            x = j;
            y = -i + height;

            if(x >= 0 && x < width && y >= 0 && y < height){
                pre_pixel = finalImage.bits() + y * width * 4  + x * 4;
                aft_pixel = newImage->bits() + i * width * 4 + j * 4;
                memcpy(aft_pixel, pre_pixel, 4);
           }
        }
   }
    finalImage = *newImage;
    delete newImage;
    return finalImage;
}

//方框滤波
QImage Function::squarePicture() {
    lastImage = finalImage;

    int width = finalImage.width();
    int height = finalImage.height();

    int sum[4] = {0};
    int num = 0;

    QImage* newImage = new QImage(width, height, QImage::Format_ARGB32);
    unsigned char* pre_pixel = NULL;
    unsigned char* aft_pixel = NULL;

    for(int j = 0; j < height; j++) {
        for(int i = 0; i < width; i++) {
            //num用来计算(i,j)这个点周围3×3区域内有几个像素点，sum数组用来保存这些像素点的和
            num = 0;
            for(int i = 0; i < 4; i++)
                sum[i] = 0;

            for(int n = j + 1; n > j - 2; n--) {
                if(n < 0 || n > height) continue;
                    for(int m = i - 1; m < i + 2; m++) {
                        if(m < 0 || m > width) continue;
                        if(n == j && m == i) continue;
                        num ++;
                        pre_pixel = finalImage.bits() + n * width * 4  + m * 4;
                        for(int i = 0; i < 4; i++)
                            sum[i] += *(pre_pixel + i);
                }
            }

            aft_pixel = newImage->bits() + j * width * 4 + i * 4;
            //用sum给(i,j)这个点赋值，并判断像素值是否在0-255之间
            for(int i = 0; i < 4; i++) {
                *(aft_pixel + i) = sum[i];
                if(*(aft_pixel + i) < 0) *(aft_pixel + i) = 0;
                else if(*(aft_pixel + i) > 255) *(aft_pixel + i) = 255;
                else continue;
            }
        }
    }

    finalImage = *newImage;
    delete newImage;
    return finalImage;
}

//比较两个像素的大小
unsigned char* max(unsigned char* a, unsigned char* b) {
    int m = 0, n = 0;
    for(int i = 0; i < 4; i++) {
        m += *(a + i);
        n += *(b + i);
    }
    if(m > n) return a;
    else return b;
}

//插入排序
void insertsort(unsigned char* a[], int n) {
    for (int i = 1; i < n; i++) {
        unsigned char *temp = a[i];
        int j = i;
        while (j > 0 && max(temp, a[j-1])) {
            a[j] = a[j - 1];
            j--;
        }
        a[j] = temp;
    }
}

//中值滤波
QImage Function::midPicture() {
    lastImage = finalImage;

    int width = finalImage.width();
    int height = finalImage.height();

    unsigned char *sum[9] = {NULL};
    int num = 0;

    QImage* newImage = new QImage(width, height, QImage::Format_ARGB32);
    unsigned char* pre_pixel = NULL;
    unsigned char* aft_pixel = NULL;

    for(int j = 0; j < height; j++) {
        for(int i = 0; i < width; i++) {
            //num用来计算(i,j)这个点周围3×3区域内有几个像素点，sum数组用来保存这些像素点的指针
            num = 0;
            for(int i = 0; i < 9; i++)
                sum[i] = NULL;

            //找出(i,j)这个点周围3×3区域内的像素点并赋值给sum进行排序
            for(int n = j + 1; n > j - 2; n--) {
                if(n < 0 || n > height) continue;
                    for(int m = i - 1; m < i + 2; m++) {
                        if(m < 0 || m > width) continue;
                        pre_pixel = finalImage.bits() + n * width * 4  + m * 4;
                        sum[num++] = pre_pixel;
                }
            }
            insertsort(sum, num);

            //选取像素的中间值赋给(i,j)这个点，并判断像素值是否在0-255之间
            aft_pixel = newImage->bits() + j * width * 4 + i * 4;
            if(num % 2 == 0) {
                num /= 2;
                for(int i = 0; i < 4; i++) {
                    *(aft_pixel + i) = (int)(((*(sum[num] + i)) + (*(sum[num-1] + i))) / 2);
                    if(*(aft_pixel + i) < 0) *(aft_pixel + i) = 0;
                    else if(*(aft_pixel + i) > 255) *(aft_pixel + i) = 255;
                    else continue;
                }
            }
            else {
                num = num / 2.0 - 0.5;
                for(int i = 0; i < 4; i++) {
                    *(aft_pixel + i) = *(sum[num] + i);
                    if(*(aft_pixel + i) < 0) *(aft_pixel + i) = 0;
                    else if(*(aft_pixel + i) > 255) *(aft_pixel + i) = 255;
                    else continue;
                }
            }
        }
    }

    finalImage = *newImage;
    delete newImage;
    return finalImage;
}

//高斯滤波
QImage Function::gaosiPicture() {
    lastImage = finalImage;

    int width = finalImage.width();
    int height = finalImage.height();

    double sum[4] = {0};
    double sigma = 1.5;//sigma表示点的标准差
    double weight[9] = {0};
    int num = 0;

    //计算(i,j)这个点周围3×3区域内每一点的权重
    for(int j = -1; j < 2; j++)
        for(int i = -1; i < 2; i++)
            weight[num++] = (1/(2*PI*sigma*sigma)) * pow(e, (-(i*i+j*j)/2/sigma/sigma));
    for(int i = 0; i < num; i++)
        sum[0] += weight[i];
    for(int i = 0; i < num; i++)
        weight[i] /= sum[0];

    QImage* newImage = new QImage(width, height, QImage::Format_ARGB32);
    unsigned char* pre_pixel = NULL;
    unsigned char* aft_pixel = NULL;

    for(int j = 0; j < height; j++) {
        for(int i = 0; i < width; i++) {
            //sum数组用来保存这些像素点的加权和
            num = 0;
            for(int i = 0; i < 4; i++)
                sum[i] = 0;

            for(int n = j + 1; n > j - 2; n--) {
                if(n < 0 || n > height) {
                    num++;
                    continue;
                }
                for(int m = i - 1; m < i + 2; m++) {
                    if(n < 0 || n > height || m < 0 || m > width) {
                        num++;
                        continue;
                    }
                    num ++;
                    pre_pixel = finalImage.bits() + n * width * 4  + m * 4;
                    for(int i = 0; i < 4; i++)
                        sum[i] += (*(pre_pixel + i)) * weight[num];
                }
            }

            //选取像素加权平均值赋给(i,j)这个点，并判断像素值是否在0-255之间
            aft_pixel = newImage->bits() + j * width * 4 + i * 4;
            for(int i = 0; i < 4; i++) {
                *(aft_pixel + i) = (int)sum[i];
                if(*(aft_pixel + i) < 0) *(aft_pixel + i) = 0;
                else if(*(aft_pixel + i) > 255) *(aft_pixel + i) = 255;
                else continue;
            }
        }
    }

    finalImage = *newImage;
    delete newImage;
    return finalImage;
}


//均值滤波
QImage Function::averagePicture() {
    lastImage = finalImage;

    int width = finalImage.width();
    int height = finalImage.height();

    int sum[4] = {0};
    int num = 0;

    QImage* newImage = new QImage(width, height, QImage::Format_ARGB32);
    unsigned char* pre_pixel = NULL;
    unsigned char* aft_pixel = NULL;

    for(int j = 0; j < height; j++) {
        for(int i = 0; i < width; i++) {
            num = 0;
            for(int i = 0; i < 4; i++)
                sum[i] = 0;

            for(int n = j + 1; n > j - 2; n--) {
                if(n < 0 || n > height) continue;
                    for(int m = i - 1; m < i + 2; m++) {
                        if(m < 0 || m > width) continue;
                        if(n == j && m == i) continue;
                        num ++;
                        pre_pixel = finalImage.bits() + n * width * 4  + m * 4;
                        for(int i = 0; i < 4; i++)
                            sum[i] += *(pre_pixel + i);
                }
            }

            aft_pixel = newImage->bits() + j * width * 4 + i * 4;
            for(int i = 0; i < 4; i++)
                *(aft_pixel + i) = sum[i] / num;
        }
    }

    finalImage = *newImage;
    delete newImage;
    return finalImage;
}

//吸管
QImage Function::strawPicture() {

}

//油漆桶
QImage Function::bucketPicture() {

}

//画笔
QImage Function::paintPicture() {

}

//裁剪
QImage Function::scissorsPicture() {

}

//拼图
QImage Function::jigsawPicture() {

}


